﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml.Linq;
using Microsoft.Xna.Framework;

namespace Pavilion
{
    public class GameItem
    {
        public event Action<GameTime> UpdateLogic;
        public event Action<GameItem> Disposed;
        public event Action<bool> EnabledChanged;
        public event Action<GameItem, GameToolBase> GameToolLoaded;

        public DrawVisibilityGroup DrawVisibilityGroup { get; private set; }
        public string Name { get; set; }
        public bool IsVisible { get { return DrawVisibilityGroup.IsVisible; } set { DrawVisibilityGroup.IsVisible = value; } }
        public bool IsEnabled { get { return isEnabled; } set { SetIsEnabled(value); } }
        
        private Dictionary<string, GameToolBase> gameToolDictionary;
        private bool isEnabled;

        public GameItem(string itemName)
        {
            this.Name = itemName;
            this.IsEnabled = true;

            DrawVisibilityGroup = new DrawVisibilityGroup();
            gameToolDictionary = new Dictionary<string, GameToolBase>();
        }

        public void Dispose()
        {
            foreach (GameToolBase gameTool in gameToolDictionary.Values)
                gameTool.Dispose();

            gameToolDictionary.Clear();

            UpdateLogic = null;
            EnabledChanged = null;
            gameToolDictionary = null;

            OnDipsosed();
        }

        internal void Update(GameTime gameTime)
        {
            if (IsEnabled) { OnUpdateLogic(gameTime); }
        }

        public T ObtainTool<T>() where T : GameToolBase
        {
            return ObtainTool(typeof(T).Name) as T;
        }

        public GameToolBase ObtainTool(string toolName)
        {
            if (!gameToolDictionary.ContainsKey(toolName))
                CreateTool(toolName);

            return gameToolDictionary[toolName];
        }

        public bool ContainsTool<T>() where T : GameToolBase
        {
            return ContainsTool(typeof(T).Name);
        }

        public bool ContainsTool(string toolName)
        {
            return gameToolDictionary.ContainsKey(toolName);
        }

        public bool RemoveTool<T>() where T : GameToolBase
        {
            return RemoveTool(typeof(T).Name);
        }

        public bool RemoveTool(string toolName)
        {
            if (ContainsTool(toolName))
            {
                ObtainTool(toolName).Dispose();
                return gameToolDictionary.Remove(toolName);
            }

            return false;
        }

        private void CreateTool(string toolName)
        {
            if (ContainsTool(toolName))
                return;

            GameToolBase createdTool = GameEngine.CreateLocalInstance<GameToolBase>("Pavilion.GameTools.dll", toolName, this);
            Type toolType = createdTool.GetType();

            while (toolType != typeof(GameToolBase))
            {
                gameToolDictionary.Add(toolType.Name, createdTool);
                toolType = toolType.BaseType;
            }

            createdTool.Load();
            OnGameToolLoaded(createdTool);
        }

        public override string ToString() { return Name; }

        private void SetIsEnabled(bool value)
        {
            if (isEnabled == value)
                return;

            isEnabled = value;
            OnEnabledChanged();
        }

        private void OnEnabledChanged()
        {
            if (EnabledChanged != null)
                EnabledChanged(IsEnabled);
        }

        private void OnDipsosed()
        {
            if (Disposed != null)
                Disposed(this);

            Disposed = null;
        }

        private void OnUpdateLogic(GameTime gameTime)
        {
            if (UpdateLogic != null)
                UpdateLogic(gameTime);
        }

        private void OnGameToolLoaded(GameToolBase gameTool)
        {
            if (GameToolLoaded != null)
                GameToolLoaded(this, gameTool);
        }
    }
}
